<?php
  /**
   * This is the Master class which includes and instantiates all Core classes
   *
   * @author Macdonald Terrence Robinson
   * @package Core
   *
   */

  require_once dirname(__FILE__).'/Session.php';
  require_once dirname(__FILE__).'/Get.php';
  require_once dirname(__FILE__).'/Post.php';
  require_once dirname(__FILE__).'/Cookie.php';

  require_once dirname(__FILE__).'/FileSystem.php';
  require_once dirname(__FILE__).'/Utility.php';
  require_once dirname(__FILE__).'/Parser.php';
  require_once dirname(__FILE__).'/XML.php';

  //require_once dirname(__FILE__).'/URI.php';
  //require_once dirname(__FILE__).'/Router.php';

  require_once dirname(__FILE__).'/SiteMap.php';
  require_once dirname(__FILE__).'/../Config.php';

  require_once dirname(__FILE__).'/ErrorHandler.php';  
  require_once dirname(__FILE__).'/../libs/SelectForm.php';
  require_once dirname(__FILE__).'/ControlHelp.php';
  //require_once dirname(__FILE__).'/HTML.php';
  //require_once dirname(__FILE__).'/Cache.php';

  //require_once dirname(__FILE__).'/XSS.php';

  final class Master
  {
    private static $db = NULL;    
    private static $mainController = NULL;
    private static $currentController = NULL;

    public static function loadCoreClass($className, $arguments = array())
    {
      $path = Config::$siteDir.$className.'.php';
      if(!class_exists($className))
          require_once dirname(__FILE__).$path;

      return Master::initClass($className, $arguments);
    }

    public static function init()
    {      
      Session::init();
      Post::init();
      Get::init();
      Cookie::init();

      Config::init();      
      //URI::init();
      //Router::init();
            
      //XSS::init();
      
      //self::customUrlHandler();



      //Parser::init();

      //Parser::initCurrentNodeAttributes();

      if(Config::$dbConnect)
        self::connectToDB();      
      return true;
    }

    public static function connectToDB()
    {
      if(self::$db == NULL)
      {
        $dbSettings = array();

        $dbSettings['dbType'] = isset(Config::$dbSettings['dbType']) ? Config::$dbSettings['dbType'] : '';
        $dbSettings['odbcDriver'] = isset(Config::$dbSettings['odbcDriver']) ? Config::$dbSettings['odbcDriver'] : '';
        $dbSettings['dbHost'] = isset(Config::$dbSettings['dbHost']) ? Config::$dbSettings['dbHost'] : '';
        $dbSettings['dbName'] = isset(Config::$dbSettings['dbName']) ? Config::$dbSettings['dbName'] : '';
        $dbSettings['dbUser'] = isset(Config::$dbSettings['dbUser']) ? Config::$dbSettings['dbUser'] : '';
        $dbSettings['dbPassword'] = isset(Config::$dbSettings['dbPassword']) ? Config::$dbSettings['dbPassword'] : '';
        $dbSettings['connectionString'] = isset(Config::$dbSettings['connectionString']) ? Config::$dbSettings['connectionString'] : '';
        
        self::$db = self::loadCoreClass('DB', $dbSettings);        
      }

      return self::$db;
    }

    /** @return BaseController */
    public static function getCurrentController()
    {      

      return self::$currentController;
    }
    public static function getMainController()
    {
      if(self::$mainController == NULL)
        self::$mainController = self::loadCoreClass('MainController');

      return self::$mainController;
    }

    /** @return BaseController */
    public static function start()
    {
      self::getCurrentController();      
    }
    /**
     * Loads a controller
     * @return MainController
     */
    public static function loadController($className, $functionName, $params = array())
    {      
      if($className == '')
        $className = Config::$defaultController;

      if($functionName == '')
        $functionName = Config::$defaultFunction;

      self::$currentController = Master::loadAndInitClass($className, $params,'', Config::$controllersDir);

      return Master::initFunction(self::$currentController, $functionName, $params);
    }

    public static function getClassFilePath($className)
    {
      $possibleDirs = array();
      $possibleDirs[] = Config::$coreDir;
      $possibleDirs[] = Config::$controllersDir;

      foreach ($possibleDirs as $key=>$value)
      {
        $filePath = self::getRealPath($value.$className.'.php');

        if( $filePath == '' )
          continue;

        return $filePath;
      }

      return '';
    }

    public static function loadAndInitClass($className, array $arguments = array(), $fromFile = '', $inDir = '')
    {      
      if(($inDir === '') && ($fromFile === ''))
        $filePath = self::getClassFilePath($className);
      else
      {
        if($fromFile == '')
          $filePath = $inDir.$className.'.php';
        else
          $filePath = $fromFile;

        if( ($filePath = self::getRealPath($filePath)) == '' )
        {
          //Master::getMainController()->redirectToHome();
          ErrorHandler::runTimeError("Error initializing class ( $className ) from file ( $filePath )");
          return false;
        }
      }
      
      require_once $filePath;

      return self::initClass($className, $arguments);
    }

    public static function initClass($className, array $arguments = array())
    {
      if(class_exists($className) )
      {
        try
        {
          if( count($arguments) < 2 )
          {
            $argument = (isset($arguments[0]))? $arguments[0] : '';
            return new $className($argument);
          }
          else
          {
            $class = new ReflectionClass($className);
            return $class->newInstanceArgs($arguments);
          }
        }
        catch(Exception $e)
        {
          $errorMessage = $e->getMessage();
          ErrorHandler::runTimeError($errorMessage);
        }
      }

      return NULL;
    }

    public static function initFunction( $object, $functionName, $arguments )
    {
      try
      {
        if( is_string($object) )
        {
          $reflection = new ReflectionClass($object);
          $method = $reflection->getMethod($functionName);
          return $method->invoke($object, $arguments);
        }
        else if( Utility::isFunctionInObject($object, $functionName) && ( count($arguments) < 2 ))
        {
          $argument = (isset($arguments[0]))? $arguments[0] : '';
          return $object->$functionName($argument);
        }
        else
        {
          $reflectionMethod = new ReflectionMethod( $object, $functionName );
          return $reflectionMethod->invokeArgs($object, $arguments);
        }
      }
      catch(Exception $e)
      {
        //return self::getCurrentController()->catchAll();
        //$reflectionMethod = new ReflectionMethod( self::getCurrentController(), 'catchAll' );
        //return $reflectionMethod->invokeArgs(self::getCurrentController(), array()) ;
      }
    }
    
    public static function getRealPath( $path )
    {
      $segments = explode( Config::$directorySeperator, $path );

      $fileName = $segments[ count($segments)-1 ];
      $segments[ count($segments)-1 ] = '';
      $dir = implode(Config::$directorySeperator, $segments);

      $path = $dir.$fileName;

      $patterns = array();
      $patterns[] = $path;

      if( FileSystem::fileExists($path) )
        return $path;

      $path = $dir.strtolower($fileName);
      if( !in_array($path, $patterns) && ( FileSystem::fileExists( $path ) ))
        return $path;
      $patterns[] = $path;

      $path = $dir.ucfirst( strtolower($fileName) );
      if( !in_array($path, $patterns) && FileSystem::fileExists( $path ) )
        return $path;
      $patterns[] = $path;

      $path = $dir.strtoupper($fileName);
      if( !in_array($path, $patterns) && FileSystem::fileExists( $path ) )
        return $path;
      $patterns[] = $path;

      $path = $dir.ucfirst(strtolower($fileName));
      if( !in_array($path, $patterns) && FileSystem::fileExists( $path ) )
        return $path;
      $patterns[] = $path;

      return '';
    }

  }
?>
